package com.mall.mymall.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mall.mymall.common.Result;
import com.mall.mymall.dao.dto.*;
import com.mall.mymall.dao.dto.querypage.OrderPageRequest;
import com.mall.mymall.dao.entity.*;
import com.mall.mymall.mapper.*;
import com.mall.mymall.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.lucene.search.grouping.LongRangeGroupSelector;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.beans.Transient;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 十里坡
 * @since 2025-03-06
 */
@Service
public class OrdersServiceImpl extends ServiceImpl<OrdersMapper, Orders> implements OrdersService {

    @Autowired
    private OrderDetailsService orderDetailsService;

    @Autowired
    private OrderDetailsMapper orderDetailsMapper;

    @Autowired
    private AddressesService addressesService;

    @Autowired
    private RefundsService refundsService;

    /**
     * 分页查询订单信息
     *
     * @param orderPageRequest 订单分页查询请求对象，包含查询参数和分页信息
     * @return 返回一个 QueryDto 对象，包含订单数据和总记录数
     */
    @Override
    public QueryDto<OrderDto> pageOrders(OrderPageRequest orderPageRequest) {
        // 查询所有 OrderSelectDto 数据
        List<OrderSelectDto> orderSelectDtos = baseMapper.selectQrderSelectDto(orderPageRequest.getQuery());

        // 将 OrderSelectDto 转换为 OrderDto
        List<OrderDto> orderDtos = convertToOrderDto(orderSelectDtos);

        // 分页处理
        int page = orderPageRequest.getPageRequestDto().getPage();
        int size = orderPageRequest.getPageRequestDto().getSize();
        int total = orderDtos.size();
        List<OrderDto> paginatedOrderDtos = orderDtos.stream().skip((long) (page - 1) * size).limit(size).collect(Collectors.toList());

        // 封装返回结果
        QueryDto<OrderDto> result = new QueryDto<>();
        result.setTotal(total);
        result.setRecords(paginatedOrderDtos);

        return result;
    }


    /**
     * 将 OrderSelectDto 列表转换为 OrderDto 列表
     * 此方法的主要作用是将从数据库查询得到的 OrderSelectDto 对象列表转换为 OrderDto 对象列表，
     * 并在每个 OrderDto 对象中填充对应的产品列表
     *
     * @param orderSelectDtos 数据库查询结果转换得到的 OrderSelectDto 列表
     * @return 转换后的 OrderDto 列表
     */
    private List<OrderDto> convertToOrderDto(List<OrderSelectDto> orderSelectDtos) {
        // 使用 Map 来存储每个订单的 OrderDto 对象，以便在遍历过程中快速查找和更新
        Map<Integer, OrderDto> orderDtoMap = new HashMap<>();

        // 遍历输入的 OrderSelectDto 列表
        for (OrderSelectDto orderSelectDto : orderSelectDtos) {
            Integer orderId = orderSelectDto.getOrderId();
            // 检查当前订单是否已经创建了 OrderDto 对象
            if (!orderDtoMap.containsKey(orderId)) {
                // 创建新的 OrderDto 对象，并设置其基本属性
                OrderDto orderDto = new OrderDto();
                orderDto.setOrderId(orderSelectDto.getOrderId());
                orderDto.setCreatedAt(orderSelectDto.getCreatedAt());
                orderDto.setOrderStatus(orderSelectDto.getOrderStatus());
                orderDto.setTotalPrice(orderSelectDto.getTotalPrice());
                orderDto.setUserId(orderSelectDto.getUserId());
                orderDto.setUserName(orderSelectDto.getUserName());
                orderDto.setStoreId(orderSelectDto.getStoreId());
                orderDto.setStoreName(orderSelectDto.getStoreName());
                orderDto.setQuantity(orderSelectDto.getQuantity());
                orderDto.setStoreAddress(orderSelectDto.getStoreAddress());
                orderDto.setAddress(orderSelectDto.getAddress());
                // 初始化订单的产品列表
                orderDto.setOrderProductDtos(new ArrayList<>());
                // 将新创建的 OrderDto 对象存入 Map 中
                orderDtoMap.put(orderId, orderDto);
            }

            // 获取当前订单的 OrderDto 对象
            OrderDto orderDto = orderDtoMap.get(orderId);

            // 创建产品对象并添加到订单的产品列表中
            OrderProductDto orderProductDto = new OrderProductDto();
            orderProductDto.setProductId(orderSelectDto.getProductId());
            orderProductDto.setProductName(orderSelectDto.getProductName());
            orderProductDto.setPrice(orderSelectDto.getProductPrice()+"");
            orderProductDto.setOrderPrice(orderSelectDto.getOrderPrice());
            orderProductDto.setProductImage(orderSelectDto.getProductImage());
            orderProductDto.setQuantity(orderSelectDto.getQuantity());
            orderDto.getOrderProductDtos().add(orderProductDto);
        }

        // 将 Map 中的 OrderDto 对象转换为 List 返回
        return new ArrayList<>(orderDtoMap.values());
    }

    /**
     * 将OrderDto转换为OrderSelectDto列表
     * 此方法用于处理订单DTO，将其属性复制到一个新的OrderSelectDto对象中，
     * 并将其关联的产品列表也转换为OrderSelectDto对象，每个产品信息都附加在OrderSelectDto上
     *
     * @param orderDto 订单DTO对象，包含订单信息和关联的产品信息
     * @return 一个OrderSelectDto对象的列表，每个对象对应订单中的一个产品
     */
    public List<OrderSelectDto> convertOrderDtoToOrderSelectDto(OrderDto orderDto) {
        // 创建OrderSelectDto的实例
        OrderSelectDto orderSelectDto = new OrderSelectDto();

        // 使用BeanUtils拷贝OrderDto的属性到OrderSelectDto
        BeanUtils.copyProperties(orderDto, orderSelectDto);

        // 处理OrderProductDto列表
        List<OrderProductDto> orderProductDtos = orderDto.getOrderProductDtos();
        List<OrderSelectDto> orderSelectDtoList = new ArrayList<>();

        // 遍历每个OrderProductDto，为每个产品创建一个OrderSelectDto的副本
        for (OrderProductDto orderProductDto : orderProductDtos) {
            // 为每个OrderProductDto创建一个OrderSelectDto的副本
            OrderSelectDto dtoCopy = new OrderSelectDto();
            BeanUtils.copyProperties(orderSelectDto, dtoCopy);

            // 设置OrderProductDto的属性到OrderSelectDto
            dtoCopy.setProductId(orderProductDto.getProductId());
            dtoCopy.setProductName(orderProductDto.getProductName());
            dtoCopy.setProductPrice(new BigDecimal(orderProductDto.getPrice()));
            dtoCopy.setProductImage(orderProductDto.getProductImage());
            dtoCopy.setOrderPrice(orderProductDto.getOrderPrice());
            dtoCopy.setQuantity(orderProductDto.getQuantity());

            // 添加到列表
            orderSelectDtoList.add(dtoCopy);
        }

        // 返回转换后的OrderSelectDto列表
        return orderSelectDtoList;
    }

    /**
     * 根据订单ID删除订单及其详细信息
     *
     * @param orderId 订单ID
     * @return 如果订单及其详细信息被成功删除，返回true；否则返回false
     */
    @Override
    @Transient // 标记该方法不是数据库操作方法，避免框架的事务管理
    public boolean deleteById(Integer orderId) {
        // 删除订单详细信息
        boolean a = orderDetailsService.remove(new QueryWrapper<OrderDetails>().eq("order_id", orderId));
        // 删除订单本身
        boolean b = removeById(orderId);
        // 只有当订单和订单详细信息都被成功删除时，才返回true
        return a & b;
    }

    @Override
    @Transactional
    public boolean update(OrderDto orderDto, Integer orderId) {
        // 将OrderDto转换为OrderSelectDto列表
        List<OrderSelectDto> orderSelectDtos = convertOrderDtoToOrderSelectDto(orderDto);

        // 1. 更新订单主表
        Orders order = this.getById(orderDto.getOrderId());
        if (order == null) {
            return false; // 如果订单不存在，返回false
        }

        // 使用BeanUtils拷贝OrderDto的属性到Order实体
        BeanUtils.copyProperties(orderDto, order);
        this.updateById(order);

        // 2. 处理订单详情表
        List<OrderDetails> existingOrderDetails = orderDetailsMapper.selectList(new QueryWrapper<OrderDetails>().eq("order_id", orderDto.getOrderId()));

        // 创建一个Map，用于快速查找OrderSelectDto中的产品
        Map<Integer, OrderSelectDto> productDtoMap = new HashMap<>();
        for (OrderSelectDto orderSelectDto : orderSelectDtos) {
            productDtoMap.put(orderSelectDto.getProductId(), orderSelectDto);
        }

        // 分离出需要删除、更新和新增的OrderDetail
        List<OrderDetails> toDelete = new ArrayList<>();
        List<OrderDetails> toUpdate = new ArrayList<>();
        List<OrderDetails> toInsert = new ArrayList<>();

        // 遍历现有的OrderDetail
        for (OrderDetails orderDetail : existingOrderDetails) {
            OrderSelectDto orderSelectDto = productDtoMap.get(orderDetail.getProductId());
            if (orderSelectDto == null) {
                // 如果OrderDetail中的产品在OrderSelectDto中不存在，则标记为删除
                toDelete.add(orderDetail);
            } else {
                // 如果存在，则标记为更新
                Addresses addresses = addressesService.getAddressesByNameAndUserId(orderSelectDto.getAddress(), orderSelectDto.getUserId());
                BeanUtils.copyProperties(orderSelectDto, orderDetail);
                orderDetail.setOrderId(orderDto.getOrderId()); // 确保订单ID不变
                orderDetail.setPrice(orderSelectDto.getOrderPrice());
                orderDetail.setQuantity(orderSelectDto.getQuantity());
                orderDetail.setAddressId(addresses.getAddressId());
                toUpdate.add(orderDetail);

                // 从Map中移除已处理的产品
                productDtoMap.remove(orderDetail.getProductId());
            }
        }

        // 剩余的OrderSelectDto为需要新增的OrderDetail
        for (OrderSelectDto orderSelectDto : productDtoMap.values()) {
            Addresses addresses;
            addresses = addressesService.getAddressesByNameAndUserId(orderSelectDto.getAddress(), orderSelectDto.getUserId());

            OrderDetails newOrderDetail = new OrderDetails();
            BeanUtils.copyProperties(orderSelectDto, newOrderDetail);
            newOrderDetail.setOrderId(orderDto.getOrderId());
            newOrderDetail.setPrice(orderSelectDto.getOrderPrice());
            newOrderDetail.setAddressId(addresses.getAddressId());
            toInsert.add(newOrderDetail);
        }

        // 执行批量删除
        if (!toDelete.isEmpty()) {
            List<Integer> deleteIds = toDelete.stream().map(OrderDetails::getDetailId).collect(Collectors.toList());
            orderDetailsMapper.deleteBatchIds(deleteIds);
        }

        // 执行批量更新
        if (!toUpdate.isEmpty()) {
            orderDetailsMapper.updateBatchIds(toUpdate);
        }

        // 执行批量插入
        if (!toInsert.isEmpty()) {
            orderDetailsMapper.saveBatch(toInsert);
        }

        return true;
    }


    /**
     * 添加订单及其详情
     *
     * @param orderDto 订单数据传输对象，包含订单和订单详情信息
     * @return 总是返回true，表示操作成功；如果地址找不到，将抛出异常
     * <p>
     * 此方法处理订单的添加操作，包括订单主表和订单详情表的插入
     * 它首先将订单信息插入订单主表，然后将订单详情插入订单详情表
     * 如果给定的用户地址在数据库中找不到，将抛出运行时异常
     * <p>
     * 开启事务
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean creatOrder(OrderDto orderDto) {
        // 1. 插入订单主表
        Orders order = new Orders();
        BeanUtils.copyProperties(orderDto, order);
        this.save(order);

        // 2. 插入订单详情表
        List<OrderSelectDto> orderSelectDtos = convertOrderDtoToOrderSelectDto(orderDto);
        // 详情为空则不执行后面的逻辑
        if (orderSelectDtos.isEmpty()) {
            return true;
        }
        List<OrderDetails> toInsert = new ArrayList<>();

        // 根据 userId 和 address 查询 addressId
//        List<Address> addressesList = addressesService.list();
        // 参数校验
        if (order.getUserId() == null) {
            throw new RuntimeException("用户id不能为空");
        }
        if (orderDto.getAddress() == null) {
            throw new RuntimeException("地址不能为空");
        }
        // 得到用户名下的地址
        List<Addresses> addressesList = addressesService.findByUserId(order.getUserId());

        // 检查地址和用户之间的关联
        Addresses addr = addressesList
                .stream()
                .filter(Objects::nonNull)
                .filter(addresses -> Objects.equals(orderDto.getAddress(), addresses.getAddress()))
                .findFirst()
                .orElseThrow(() -> new RuntimeException(
                        String.format("用户ID[%s]的地址[%s]不存在", orderDto.getUserId(), orderDto.getAddress())
                ));
        // 如果没有选择商品则不走这个循环
        toInsert = orderSelectDtos
                .stream()
                .map(orderSelectDto -> {
                    // 使用stream.map进行详情表生成 更加优雅
                    OrderDetails newOrderDetail = new OrderDetails();
                    BeanUtils.copyProperties(orderSelectDto, newOrderDetail);
                    newOrderDetail.setOrderId(order.getOrderId()); // 设置外键，关联到刚刚插入的订单主表
                    newOrderDetail.setPrice(orderSelectDto.getOrderPrice());
                    newOrderDetail.setAddressId(addr.getAddressId());
                    return newOrderDetail;

                }).toList();
//        for (OrderSelectDto orderSelectDto : orderSelectDtos) {
//            OrderDetails newOrderDetail = new OrderDetails();
//            BeanUtils.copyProperties(orderSelectDto, newOrderDetail);
//            newOrderDetail.setOrderId(order.getOrderId()); // 设置外键，关联到刚刚插入的订单主表
//            newOrderDetail.setPrice(orderSelectDto.getOrderPrice());
//            // 使用筛选好的id
//            newOrderDetail.setAddressId(addr.getAddressId());
//            toInsert.add(newOrderDetail);
//        }
        // 批量插入订单详情
        if (!toInsert.isEmpty()) {
            orderDetailsMapper.saveBatch(toInsert);
        }
        return true;
    }

    @Override
    public boolean addOrder(List<OrderProductDto> productsList, Integer userId) {
        Orders orders = new Orders();
        if (productsList == null || productsList.isEmpty()) {
            orders.setTotalPrice(BigDecimal.ZERO);
        } else {
            orders.setTotalPrice(productsList.stream().map(OrderProductDto::getOrderPrice).reduce(BigDecimal::add).get());
        }
        orders.setUserId(userId);
        orders.setOrderStatus("已付款");
        orders.setCreatedAt(LocalDate.now());
        this.save(orders);
        List<OrderDetails> orderDetailsList = new ArrayList<>();
        for (OrderProductDto orderProductDto : productsList){
            OrderDetails orderDetails = new OrderDetails();
            orderDetails.setOrderId(orders.getOrderId());
            orderDetails.setProductId(orderProductDto.getProductId());
            orderDetails.setQuantity(orderProductDto.getQuantity());
            orderDetails.setPrice(BigDecimal.valueOf(Long.parseLong(orderProductDto.getPrice()) * orderProductDto.getQuantity()));
            orderDetails.setAddressId(1);
            orderDetailsList.add(orderDetails);
        }
        orderDetailsMapper.saveBatch(orderDetailsList);
        return true;
    }

    /**
     * 修改订单状态
     *
     * @param orderStatus 新的订单状态
     * @param orderId     订单ID
     * @return 状态更新是否成功
     */
    @Override
    public boolean changeStatus(String orderStatus, Integer orderId) {
        // 调用基础映射的按ID更新状态方法
        return baseMapper.updateStatusById(orderStatus, orderId);
    }

    /**
     * 处理退款申请
     *
     * @param orderId 订单ID，用于标识需要退款的订单
     * @param body    包含退款原因等信息的映射
     * @return 返回一个Result对象，包含处理结果的消息
     */
    @Override
    public Result<String> applyRefund(Integer orderId, Map<String, String> body) {
        // 检查订单是否存在
        Orders orders = this.getById(orderId);
        if (orders == null) {
            return Result.fail("订单不存在");
        }

        // 获取退单原因
        String description = body.get("description");
        if (description == null || description.isEmpty()) {
            return Result.fail("退单原因不能为空");
        }

        // 创建退款对象并复制订单信息
        Refunds refunds = new Refunds();
        BeanUtils.copyProperties(orders, refunds);
        // 设置退款原因
        refunds.setOrderStatus("待处理");
        refunds.setDescription(description);
        // 保存退款信息
        refundsService.save(refunds);

        // 更新订单状态为“退单中”，并保存退单原因
        orders.setOrderStatus("退单中");
        this.updateById(orders);

        // 返回成功结果
        return Result.success("退单申请提交成功");
    }

    @Override
    public OrderCountVo orderCount(OrderDto orderDto) {
        LocalDate endTime = LocalDate.now();
        List<OrderCountDto> counts = baseMapper.orderCountByDay(endTime.minusDays(365), endTime);
        OrderCountVo resultVo = new OrderCountVo();
        // 初始化
        resultVo.setDates(new ArrayList<>());
        resultVo.setPayed(new ArrayList<>());
        resultVo.setRefunding(new ArrayList<>());
        resultVo.setRefunded(new ArrayList<>());
        resultVo.setFinished(new ArrayList<>());

        // 数据格式转化
        Map<LocalDate, Map<String, Integer>> resultMap = counts.
                stream()
                .collect(
                        Collectors.
                                groupingBy(OrderCountDto::getOrderDate,
                                        TreeMap::new,
                                        Collectors.toMap(
                                                OrderCountDto::getOrderStatus, OrderCountDto::getOrderCount
                                        )));
        // 数据封装
        resultMap.forEach((date, Status) -> {
            resultVo.getDates().add(date);
            resultVo.getPayed().add(Status.getOrDefault("已付款", 0));
            resultVo.getRefunding().add(Status.getOrDefault("退单中", 0));
            resultVo.getRefunded().add(Status.getOrDefault("已退单", 0));
            resultVo.getFinished().add(Status.getOrDefault("已完成", 0));
        });
        return resultVo;
    }

    @Override
    public List<Orders> orderList(Integer page, Integer size, Integer userId) {
        Page<Orders> ordersPage = new Page<>(page, size);
        return baseMapper.selectPage(ordersPage, new QueryWrapper<Orders>().eq("user_id", userId)).getRecords();
    }

    @Override
    public String getStatus(Integer orderId) {
        Orders orders = baseMapper.selectById(orderId);
        return orders.getOrderStatus();
    }

}
